Vinicius Gomes Pereira
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
O que foi feito:
1) Análise univariada
Estudo da distribuição de cada feature;
Estudo da distribuição de cada feature em relação ao tipo do vinho (tinto ou branco);
2) Análise Bivariada
Separamos as features em 3 grupos (features que medem a acidez, features de compostos químicos, e outras features);
Analise da correlação feature by feature;
Analise da correlação de cada feature, com base no tipo de vinho, e na qualidade (baixa,média ou alta);
Analise da distribuição de cada de cada feature, em relação à qualidade;
Analise da distribuição de cada feature, em relação à qualidade e tipo de vinho;
Análise de regressão de cada feature, em relação a outras;
Análise de regressão de cada feature, em relação a outras, agrupando pelo tipo de vinho;
Teste de variância (ANOVA), para analisar a distribuição de cada feature, em diversos grupos diferentes (pelo tipo de vinho, pela qualidade de vinho);
3) Análise Multivariada
4) Modelagem
Comparamos os algoritmos utilizando um conjunto de validação, que corresponde a 1/3 dos dados iniciais, mantendo a proporção das classes;
Plotamos a curva de aprendizagem;
Plotamos a importância de cada feature
Confusion Matrix;
E métricas de precisão (precision, f1-score, recall);
Modelos Utilizados
1) Regressão Logística, utilizando o algoritmo One Vs The Rest, para problemas de multiclasse
2) Árvores de Decisão
3) Random Forest
4) SVM, utilizando o algoritmo One Vs The Rest, para problemas de multiclasse
5) xGBoost
6) k - Nearest Neighboors
7) Gaussian Naive Bayes (Baseline)
Aplicamos PCA para redução de dimensionalidade para melhorar a performance da Regressão Logística;
Repetimos essa modelagem para prever somente 3 classes (vinhos bons, médios e ruins)
##Importando os dados, em um dataframe
df = pd.read_csv("winequality.csv",sep=";")
#Olhando as 5 primeiras colunas
df.head()
#Vamos olhar as informações do dataframe
df.info()
Os valores de álcool naõ está do tiṕo float, alguns valaores estão corrompidos no dataset, nós iremos eliminar esses valores. Primeiro, iremos mapear todos os valores para float, depois, os valores que estão corrompidos substituiremos pela média dos valores restantes, avaliando se haverá algum impacto na classificação;
#Mapeando os valores para float, e sinalizando os valores corrompidos para -1
def map_to_float(value):
try:
return float(value)
except:
return -1
df["alcohol"] = df["alcohol"].map(lambda x : map_to_float(x))
Analisando a distribuição de valores errados
sns.countplot(df[df["alcohol"] == -1]["quality"])
Analisando a distribuição de valores não errados
sns.countplot(df[df["alcohol"] != -1]["quality"])
A maioria dos valores de qualidade são 5, 6 e 7. Os valores corrompidos de álcool corrompidos são dessas categorias de qualidade, e são poucos valores, iremos substituir esses valores pela média.
mean_alcohol = df[df["alcohol"]!=-1]["alcohol"].mean()
#Mapeando os valores para float, e sinalizando os valores corrompidos para -1
def map_to_median(x,mean):
if x ==-1:
return mean
else:
return x
df["alcohol"] = df["alcohol"].map(lambda x : map_to_median(x,mean_alcohol))
Como o número de classes de qualidade são 7, iremos criar 3 novas classes (vinho ruim, com qualidade menor que 4, vinho médio com qualidade 5 e 6, vinho excelente com qualidade maior ou igual a 7) de modo a analisar também de maneira acertiva
def map_quality_label(quality):
if quality <= 4:
return "Bad"
if quality>=5 and quality <=6:
return "Medium"
if quality>=7:
return "Great"
def map_quality_category(quality):
if quality <= 4:
return 0
if quality>=5 and quality <=6:
return 1
if quality>=7:
return 2
#Basicamente todos os valores são não nulos, do tipo float, menos as variáveis
df["quality_label"] = df["quality"].map(lambda x: map_quality_label(x))
df["quality_category"] = df["quality"].map(lambda x: map_quality_category(x))
df.describe()
Algumas observações
1) O valor máximo da feature residual_sugar (65.8) é muito maior que sua média (5.44) e seu percentil-75% o que podemos considerar como outlier.
2) O valor máximo de free_sulfur_dioxide (289.00) é muito maior que sua média (30.52) e seu percentil-75% (41.00) o que podemos considerar como outlier.
3) O valor 103.898 respectivo ao valor máximo da densidade, claramente é um outlier, o que desloca os valores de médida e variância.
Alguns valores de densidade estão fora do esperado, um dos líquidos mais densos a temperatura ambiente é o mercúrio, com densidade 13.595 kg/m3 (na S.I.). Assim, iremos remover os valores de desnidade maiores que 10. O esperado é que a densidade do vinho seja parecido com da água
df = df[df["density"]<10]
df.describe()
Os valores de densidade de alcool ficaram na normalidade
Vamos dividir os vinhos em diversos grupos:
Algumas features foram agrupadas:
#Selecionando os vinhos brancos
df_white = df[df["type"] == "White"]
#Selecionando os vinhos tintos
df_red = df[df["type"] == "Red"]
#Selecionando os vinhos de baixa qualidade
df_bad = df[df["quality_category"] == 0]
#Selecionando os vinhos de média qualidade
df_medium = df[df["quality_category"] == 1]
#Selecionando os vinhos de boa qualidade
df_great = df[df["quality_category"] == 2]
#Selecionando os vinhos brancos de baixa qualidade
df_white_bad = df_white[df_white["quality_category"] == 0]
#Selecionando os vinhos brancos de média qualidade
df_white_medium = df_white[df_white["quality_category"] == 1]
#Selecionando os vinhos brancos de boa qualidade
df_white_great = df_white[df_white["quality_category"] == 2]
#Selecionando os vinhos tintos de baixa qualidade
df_red_bad = df_red[df_red["quality_category"] == 0]
#Selecionando os vinhos tintos de média qualidade
df_red_medium = df_red[df_red["quality_category"] == 1]
#Selecionando os vinhos tintos de boa qualidade
df_red_great = df_red[df_red["quality_category"] == 2]
#Colunas relacionandas a acidez
acid_columns = ["fixed acidity","volatile acidity","citric acid","pH"]
#Colunas relacionadas a compostos químicos
elements_columns = ["chlorides","free sulfur dioxide","total sulfur dioxide","sulphates","alcohol"]
#Outras Colunas
other_columns = ["residual sugar","density"]
#Inputs
columns_data = ['alcohol','chlorides','citric acid','density','fixed acidity','free sulfur dioxide','pH','quality','residual sugar','sulphates','total sulfur dioxide','type','volatile acidity']
Distribuição da qualidade de álcool
#Distribuição dos Vinhos em relação à qualidade
sns.countplot(x = df.quality, data=df)
#Distribuição dos vinhos em relação à qualidade
sns.countplot(x = df.quality_label, data=df)
Distribuição ds vinhos brancos e tintos (vermelhos)
A qualidade média do vinho branco é 5.88 e a qualidade média do vinho tinto é 5.63
sns.countplot(x = df.type, data=df, hue='type')
sns.countplot(x = df.quality, data=df,hue="type")
sns.countplot(x = df.quality_label, data=df, hue='type')
print("Qualidade vinho branco: "+str(df_white["quality"].mean()))
print("Qualidade vinho vermelho: "+str(df_red["quality"].mean()))
Análise de todas as features agrupando por tipo. Iremos avaliar melhor depois. Porém alguns valores saltam aos olhos, em relação à média:
pd.concat([df_white.describe(), df_red.describe()], axis=0, keys=['White', 'Red']).T
Análise das Features em relação a média dos vinhos ruins, bons e medianos:
bad_describe = df_bad.describe()
medium_describe = df_medium.describe()
great_describe = df_great.describe()
pd.concat([bad_describe, medium_describe, great_describe], axis=0, keys=['Bad', 'Medium', 'Great']).T
bad_describe = df_white_bad.describe()
medium_describe = df_white_medium.describe()
great_describe = df_white_great.describe()
pd.concat([bad_describe, medium_describe, great_describe], axis=0, keys=['White Bad', 'White Medium', 'White Great']).T
bad_describe = df_red_bad.describe()
medium_describe = df_red_medium.describe()
great_describe = df_red_great.describe()
pd.concat([bad_describe, medium_describe, great_describe], axis=0, keys=['Red Bad', 'Red Medium', 'Red Great']).T
def ploat_histogram_agregating_by_type(df):
colors = ["#5cb85c","#5bc0de","#d9534f"]
df_red = df[df["type"]=="Red"]
df_white = df[df["type"]=="White"]
fig, axes = plt.subplots(nrows=4, ncols=3,figsize=(20,20))
ax00, ax01, ax02, ax10, ax11, ax12, ax20,ax21,ax22, ax30, ax31, ax32 = axes.flatten()
sns.distplot(df_white["fixed acidity"],ax=ax00,color=colors[0])
sns.distplot(df_red["fixed acidity"],ax=ax00,color=colors[2])
ax00.set_title('Fixed Acidity')
sns.distplot(df_white["volatile acidity"],ax=ax01, color = colors[0])
sns.distplot(df_red["volatile acidity"],ax=ax01, color = colors[2])
ax01.set_title('Volatile Acidity')
sns.distplot(df_white["citric acid"],ax=ax02, color = colors[0])
sns.distplot(df_red["citric acid"],ax=ax02, color = colors[2])
ax02.set_title('Citric Acid')
sns.distplot(df_white["chlorides"], ax=ax10, color = colors[0])
sns.distplot(df_red["chlorides"], ax=ax10, color = colors[2])
ax10.set_title('Chlorides')
sns.distplot(df_white["free sulfur dioxide"] ,ax=ax11, color = colors[0])
sns.distplot(df_red["free sulfur dioxide"] ,ax=ax11, color = colors[2])
ax11.set_title('Free sulfur dioxide')
sns.distplot(df_red["total sulfur dioxide"],ax=ax12, color = colors[0])
sns.distplot(df_white["total sulfur dioxide"],ax=ax12, color = colors[2])
ax12.set_title("Total Sulfur Dioxide")
sns.distplot(df_white["density"],ax=ax20, color = colors[0])
sns.distplot(df_red["density"],ax=ax20, color = colors[2])
ax20.set_title("Density")
sns.distplot(df_white["pH"],ax=ax21, color = colors[0])
sns.distplot(df_red["pH"],ax=ax21, color = colors[2])
ax21.set_title("pH")
sns.distplot(df_white["sulphates"],ax=ax22, color = colors[0])
sns.distplot(df_red["sulphates"],ax=ax22, color = colors[2])
ax22.set_title("Sulphates")
sns.distplot(df_white["alcohol"], ax=ax30, color = colors[0])
sns.distplot(df_red["alcohol"], ax=ax30, color = colors[2])
ax30.set_title("Alcohol")
sns.distplot(df_white["residual sugar"],ax=ax31, color = colors[0])
sns.distplot(df_red["residual sugar"],ax=ax31, color = colors[2])
ax31.set_title("Residual Sugar")
sns.distplot(df_white["quality"], ax=ax32, color = colors[0])
sns.distplot(df_red["quality"], ax=ax32, color = colors[2])
ax32.set_title("Quality")
def ploat_histogram(df):
colors = ["#5cb85c","#5bc0de","#d9534f"]
fig, axes = plt.subplots(nrows=4, ncols=3,figsize=(20,20))
ax00, ax01, ax02, ax10, ax11, ax12, ax20,ax21,ax22, ax30, ax31, ax32 = axes.flatten()
sns.distplot(df["fixed acidity"],ax=ax00,color=colors[0]);
ax00.set_title('Fixed Acidity')
sns.distplot(df["volatile acidity"],ax=ax01, color = colors[1])
ax01.set_title('Volatile Acidity')
sns.distplot(df["citric acid"],ax=ax02, color = colors[2])
ax02.set_title('Citric Acid')
sns.distplot(df["chlorides"], ax=ax10, color = colors[0])
ax10.set_title('Chlorides')
sns.distplot(df["free sulfur dioxide"] ,ax=ax11, color = colors[1])
ax11.set_title('Free sulfur dioxide')
sns.distplot(df["total sulfur dioxide"],ax=ax12, color = colors[2])
ax12.set_title("Total Sulfur Dioxide")
sns.distplot(df["density"],ax=ax20, color = colors[0])
ax20.set_title("Density")
sns.distplot(df["pH"],ax=ax21, color = colors[1])
ax21.set_title("pH")
sns.distplot(df["sulphates"],ax=ax22, color = colors[2])
ax22.set_title("Sulphates")
sns.distplot(df["alcohol"], ax=ax30, color = colors[0])
ax30.set_title("Alcohol")
sns.distplot(df["residual sugar"],ax=ax31, color = colors[1])
ax31.set_title("Residual Sugar")
sns.distplot(df["quality"], ax=ax32, color = colors[2])
ax32.set_title("Quality")
Analisando os gŕaficos das distribuições das features
1) A distribuição de fixed acidity é normal, enviesada à esquerda, com média com x entre 6 e 8;
2) A distribuição de volatile acidity tem um máximo global perto de x = 0.25 e uns máximo local com x entre 0.5 e 0.75, e é enviesada à esquerda
3) A distribuição de citric acid tem 3 máximos locais principais (perto de x = 0, x entre 0.25 e 0.375 e x perto de 0.5), e é enviesada à esquerda
4) A distribuição de Chlorides é enviesada á esquerda com um máximo global perto de x= 0.5
5) A distribuição de Free Sulfur Dioxide é normal, enviesada à esquerda, com média perrto de x= 30
6) A distribuição de total sulfur dioxide é bimodal
7) A distribuição de Density é bimodal
8) A distribuição de pH é normal, com média perto de 3.2
9) A distribuição de Sulphates é normal enviesada à esquerda
10) A distribuição de álcool tem máximo global perto de x = 9.75
11) A distribuição de residual sugar é enviesada à esquerda, com máximo global perto de x=2.5
ploat_histogram(df)
É possível explicar um pouco das distribuições acima, analisando separadamente as distribuições dos vinhos tintos e brancos que se comportam de maneira diferente.
1) A distribuição normal do pH pode ser explicada pelo fato das distribuições normais dos vinhos tintos e brancos serem normais com médias em torno de 3.4 e 3.1, aproximadamente, gerando uma distribuição normal com média 3.2, aproximadamente
2) A distribuição bimodal de total sulfur dioxide pode ser explicada por duas distribuições normais dos vinhos tintos e brancos, com média separadas o suficiente entre si.
ploat_histogram_agregating_by_type(df)
Plotando em um heatmap a correlação entre as features. Pimeiro analizamos sem nenhum agrupamento, em seguida, avaliamos somente para vinhos tintos e somente para vinhos brancos. Depois avaliamos para os vinhos ruins, médios e bons. Há uma melhor análise de correlação, estudando os gráficos de correlação linear entre as features na próxima sessão.
As correlações com valores em módulo acima de 0.4:
1) Total sulfur dioxide tem uma alta correlação com free sulfur dioxide (0.72) , alta correlação com residual sugar (0.49) , e uma correlação negativa com volatile acidity (-0.41);
2) Citric Acid tem uma correção negativa com volatile acid (-0.4);
3) Alcohol tem uma correlação negativa acentuada com densidade (-0.71) e uma correlação positiva com quality (0.45);
4) Fixed Acid tem uma relação postiva acentuada com a densidade (0.43);
5) Density tem uma correlação positiva com residual sugar (0.53);
6) Residual Sugar tem correlação postiva com free sulfur dioxide (0.41)
As correlações mais acentuadas em relação à qualidade é : alcohol (0.45), density (-0.32) e volatile acid (-0.27)
plt.figure(figsize=(12, 12))
sns.heatmap(df[list(set(df.columns)-set(["quality_category"]))].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
Correlação dos Vinhos Brancos
plt.figure(figsize=(12, 12))
sns.heatmap(df_white.corr(),vmin=-1,vmax=1,annot=True,cbar=True)
Correlação dos Vinhos Vermelhos
plt.figure(figsize=(12, 12))
sns.heatmap(df_red[list(set(df_red.columns)-set("quality_category"))].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
A seguir, plotamos o heatmap dos vinhos considerados ruins, médios e bons, porém, não há grande mudança de correlação em relação à qualidade de maneira notória.
Correlação dos Vinhos Considerados ruims
plt.figure(figsize=(12, 12))
sns.heatmap(df_bad[list(set(df_bad.columns)-set(["quality_category"]))].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
Correlação dos Vinhos Considerados Médios
plt.figure(figsize=(12, 12))
sns.heatmap(df_medium[list(set(df_medium.columns)-set(["quality_category"]))].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
Correlação dos Vinhos Considerados Bons
plt.figure(figsize=(12, 12))
sns.heatmap(df_great[list(set(df_great.columns)-set(["quality_category"]))].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
Em seguida plotamos também um heatmap para destacar as features de acidez, em seguida outro heatmap para destacar as features de compostos químicos, em seguida as features restantes;
plt.figure(figsize=(12, 12))
sns.heatmap(df_great[acid_columns].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
plt.figure(figsize=(12, 12))
sns.heatmap(df_great[elements_columns].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
plt.figure(figsize=(12, 12))
sns.heatmap(df_great[other_columns].corr(),vmin=-1,vmax=1,annot=True,cbar=True)
def plot_box_plot(df,nrows,ncols,figsize,columns,by):
fig = plt.figure(figsize=figsize)
index=0
for element in range(nrows*ncols):
ax = fig.add_subplot(nrows,ncols,element+1)
g = sns.boxplot(x="quality", y=columns[element], hue="quality_label", data=df, palette="Set3",ax=ax)
ax.get_legend().set_visible(False)
def plot_box_plot_by_type(df,nrows,ncols,figsize,columns,by):
fig = plt.figure(figsize=figsize)
index=0
for element in range(nrows*ncols):
ax = fig.add_subplot(nrows,ncols,element+1)
g = sns.boxplot(x="quality", y=columns[element], hue="type", data=df,ax=ax,palette="Set2")
ax.get_legend().set_visible(False)
Análise de Outros Elementos em Relação à Qualidade
Iremos analizar o grupo que consideramos como "outros elementos" (densidade, álcool e residual sugar) , em relação à qualidade.
Há uma discriminação em relação à qualidade baixa, média e alta nos gráficos boxplot
1) Conseguimos perceber um caŕater descrescente na densidade em relação à qualidade, e um caráter crescente do álcool em relação à qualidade.
plot_box_plot(df,3,1,(15,20),['residual sugar','density','alcohol'],"quality_category")
Análise do Grupo de Compostos Químicos em Relação à Qualidade
Iremos analizar o grupo que consideramos como "compostos químicos" (chlorides','free sulfur dioxide','total sulfur dioxide','sulphatesr) , em relação à qualidade.
1) Conseguimos perceber uma tentência descrente da média de chlorides, em relação ao aumento da qualidade
2) Conseguimos perceber uma tentência crescente da média de free sulfur dioxide, em relação ao aumento da qualidade
plot_box_plot(df,2,2,(30,20),['chlorides','free sulfur dioxide','total sulfur dioxide','sulphates'],"quality_category")
Análise dos Elementos Ácidos
1) Citric Acid é crescente em relação ao aumento da qualidade
plot_box_plot(df,2,2,(30,20),['fixed acidity','volatile acidity','citric acid','pH'],"quality_category")
A análise dos padrãos de crescimento das features em relação à qualidade, é bem mais demarcada quando analisamos o tipo de vinho. Como veremos a seguir.
Análise em relação ao grupo outros elementos (residual sugar, density e alcohol)
1) Em relação ao residual sugar e o vinho tinto, perbemos pouca variação em relação à qualidade, e há mais variação no vinho branco desse elemento;
2) Em relação a density, há uma padrão de decrescimento em relação à qualidade, em ambos os casos;
3) Há um padrão de crescimento em relação à qualidade, em ambos os tipos de vinho;
plot_box_plot_by_type(df,3,1,(15,20),['residual sugar','density','alcohol'],"quality_category")
Análise do grupo relacionado à acidez (fixed acidity, volatile acidity , citric acid , pH )
1) Fixed Acidity em vinhos tintos tem caráter crescente em relação à qualidade, e não se consegue identidicar esse mesmo caráter tão acentudado em relação ao vinho branco;
2) Volatile Acidity em vinhos tintos tem caráter decrescente em relação ao aumento qualidade, e não se consegue identidicar esse mesmo caráter em relação ao vinho branco;
3) Citric Acid tem caráter crescente em relação à qualidade nos vinhos tintos e ao aumento da qualidade, mas não tão acentuado quanto o crescimento de citric adcid em relação à qualidade em vinhos brancos;
plot_box_plot_by_type(df,2,2,(30,20),['fixed acidity','volatile acidity','citric acid','pH'],"quality_category")
Análise do grupo compostos químicos (chlorides, free sulfur dioxide , total sulfur dioxide , sulphates )
1) Conseguimos perceber um padrão de crescimento em relação à qualidade dos Sulphates bem notório em relação aos vinhos tintos, e uma média quase constante em relação ao mesmo gráfico dos vinhos brancos;
plot_box_plot_by_type(df,2,2,(30,20),['chlorides','free sulfur dioxide','total sulfur dioxide','sulphates'],"quality_category")
def print_regression_agregating_by_type(df,nrows,ncols,columns1,columns2,figsize):
fig = plt.figure(figsize=figsize)
plt.title("Análise de Regressão, agregando pelo tipo de vinho, tinto (Vermelho), branco (Azul)")
element=1
for index,column in enumerate(columns1):
for index2, column2 in enumerate(columns2):
ax = fig.add_subplot(nrows,ncols,element)
sns.regplot(x = columns1[index], y=columns2[index2], color="red", data=df[df["type"]=="Red"],line_kws={'color': 'red'})
sns.regplot(x = columns1[index], y=columns2[index2], data=df[df["type"]=="White"],line_kws={'color': 'blue'})
element+=1
def print_regression(df,nrows,ncols,columns1,columns2,figsize):
fig = plt.figure(figsize=figsize)
plt.title("Análise de Regressão")
element=1
for index,column in enumerate(columns1):
for index2, column2 in enumerate(columns2):
ax = fig.add_subplot(nrows,ncols,element)
sns.regplot(x = columns1[index], y=columns2[index2], data=df,line_kws={'color': 'blue'})
element+=1
Por meio de um scatter plot, e destacando a linha de tendência, conseguimos analisar melhor as correlações entre as features (o que mostramos anteriormente no heatmap)
Análise do grupo ácido (fixed acidity , volatile acidity , citric acid , pH)
1) Correlação positiva
a) Volatile Acidity e Fixed Acidity
b) Citric Acid e Fixed Acid
c) pH e Volatile Acidity
2) Correlação negativa
a) pH e Fixed Acidity
b) Citric Acid e Volatile Acidity
c) Citric Acid e pH
print_regression(df,4,4,acid_columns,acid_columns,(30,30))
Análise do grupo ácido (fixed acidity , volatile acidity , citric acid , pH) agrupando pelo tipo de vinho
Na grande maioria dos casos, a curva de crescimento e decrescimento nos vinhos tintos é mais acentuada que nos vinhos brancos.
Porém , algumas tendências que saltam aos olhos:
1) Volatile Acidity e Fixed Acidity tem correlação negativa nos vinhso tintos e correção ligeiramente positiva nos vinhos brancos
2) Volatile Acidity e pH tem correlação bem positiva em vinhos tintos e ligeiramente negativa nos vinhos brancos
print_regression_agregating_by_type(df,4,4,acid_columns,acid_columns,(30,30))
Análise do Grupo Ácido (fixed acidity, volatile acidity, 'citric acid, pH) em relação ao Grupo de Outros Elementos ( chlorides, free sulfur dioxide, total sulfur dioxide, sulphates, alcohol)
1) Correlação Positiva
a) Fixed Acidity e Chlorides
b) Fixed Acidity e Sulphates
c) Volatile Acid e Chlorides
d) Volatile Acid e Sulphates
e) Citric Acid e Total Sulfur Dioxide
f) pH e Sulphates
g) pH e Alcohol
2) Correlação Negativa
a) Fixed Acidity e Free Sulfur Dioxide
b) Fixed Acidity e Total Sulfur Dioxide
c) Fixed Acidity e Alcohol
d) Volatile Acidity e Free Sulfur Dioxide
e) Volatile Acidity e Total Sulfur Dioxide
f) Total Sulfur Dioxide e pH
Correlações mais notórias
1) Total Sulfur Dioxide e Fixed Acidity (negativo)
2) Total Sulfur Dioxide e Volatile Acidity (negativo)
3) Total Sulfur Dioxide e Citic Acid (positiva)
print_regression(df,len(acid_columns),len(elements_columns),acid_columns,elements_columns,(30,30))
Análise do Grupo Ácido (fixed acidity, volatile acidity, citric acid, pH) em relação ao Grupo de Compostos Químicos ( chlorides, free sulfur dioxide, total sulfur dioxide, sulphates, alcohol) agrupados pelo Tipo de Vinho
Há um comportamento diferente em relação a fixed acidity e total sulfur dioxide. Enquanto em vinhos tintos o comportamento é decrescente, a correlação é positiva para os vinhos brancos. Mesmo comportamento para as features volatile acid e alcohol e pH e sulphates
Há um comportamento diferente em relação a fixed acidity e sulphates. Enquanto em vinhos tintos o comportamento é crescente, a correlação é negativa para os vinhos brancos. Mesmo comportamento para as features volatile acidity e free sulfur dioxide, citric acid e alcohol;
print_regression_agregating_by_type(df,len(acid_columns),len(elements_columns),acid_columns,elements_columns,(30,30))
Análise do Grupo Ácido (fixed acidity, volatile acidity, citric acid, pH) em relação ao Grupo de Outros Elementos ( density e residual sugar)
Correlação positiva
a) fixed acidity e density
b) volatile acidity e density
c) citric acid e e residual sugar
Correlação negativa
a) fixed acidity e residual sugar
b) volatile acidity e residual sugar
c) pH e e residual sugar
Correlação mais notória
a) Density e Fixed Acidity (positiva)
print_regression(df,len(acid_columns),len(other_columns),acid_columns,other_columns,(15,15))
Análise do Grupo Ácido (fixed acidity, volatile acidity, citric acid, pH) em relação ao Grupo de Outros Elementos ( density e residual sugar) agrupados pelo tipo de Vinho
Somente pH e residual sugar tem comportamento diferente para os vinhos tintos e brancos. Para os vinhos brancos, a correlação é marcadamente negativa
print_regression_agregating_by_type(df,len(acid_columns),len(other_columns),acid_columns,other_columns,(15,15))
Análise do Grupo de Outros Elementos ( density e residual sugar)
Há uma correlação crescente entre residual sugar e density
print_regression(df,len(other_columns),len(other_columns),other_columns,other_columns,(15,15))
Análise do Grupo de Outros Elementos ( density e residual sugar) agrupados pelo tipo de vinho
O comportamente é o mesmo nos vinhos tintos e brancos
print_regression_agregating_by_type(df,len(other_columns),len(other_columns),other_columns,other_columns,(15,15))
Análise do Grupo de Compostos Químicos ( chlorides, free sulfur dioxide, total sulfur dioxide, sulphates, alcohol) e, relação ao Grupo de Outros Elementos (Density e Residual Sugar)
Correlação Positiva
a) Residual Sugar e Free Sulfur Dioxide
b) Residual Sigar e Total Sulfur Dioxide
c) Density e Sulphates
d) Density e Chlorides
Correlação Negativa
a) Residual Sugar e Alcohol
b) Alcohol e Density
Correlação mais notória
a) Residual Sugar e Total Sulfur Dioxide (positiva)
b) Alcohol e Density (negativa)
c) Alcohol e Residual Sugar (negativa)
print_regression(df,len(other_columns),len(elements_columns),other_columns,elements_columns,(30,15))
Análise do Grupo de Compostos Químicos ( chlorides, free sulfur dioxide, total sulfur dioxide, sulphates, alcohol) e, relação ao Grupo de Outros Elementos (Density e Residual Sugar) agrupados pelo tipo de vinho
Há um comportamento diferente entre alcohol e residual sugar. Em vinhos tintos, quanto mais alcohol, mais residual sugar. Comportamente diferente para vinhos brancos.
print_regression_agregating_by_type(df,len(other_columns),len(elements_columns),other_columns,elements_columns,(30,15))
Queremos avaliar se nos grupos que dividiremos a seguir , as features são todos parte de uma população maior ou populações distintas com características diferentes. Iremos avalirar em relação ao tipo de vinho e a qualidade de vinho.
1) Vinho Branco e Vinho Tinto (em relação ao tipo do vinho):
2) Vinho Ruim, Médio e Ótimo (em relação a qualidade do vinho):
from scipy.stats import f_oneway
print("Análise nos vinhos tintos e brancos")
for column in columns_data:
if column!="type":
F, p = f_oneway(df_red[column],df_white[column])
if(p>=0.05):
print("Hipótese Nula Aceita. Estatística F:"+str(F)+" ; p-value:"+str(p))
else:
print("Hipótese Nula Rejeitada. Estatística F:"+str(F)+" ; p-value:"+str(p))
print("Análise nos vinhos pela qualidade")
for column in columns_data:
if column!="type":
F, p = f_oneway(df_bad[column],df_medium[column],df_great[column])
if(p>=0.05):
print("Hipótese Nula Aceita. Estatística F:"+str(F)+" ; p-value:"+str(p))
else:
print("Hipótese Nula Rejeitada. Estatística F:"+str(F)+" ; p-value:"+str(p))
Para uma melhor visualização, resolvemos utilzar a qualidade do vinho somente em relação a ele ser Bom, Médio ou Ótimo
Foi feita uma análise combinando os conjuntos que separamos de features (features com respeito a acidez, compostos químicos, outros elementos). Porém, não conseguimos identifar nada de relevante. As visualizações a seguir diz respeito a essas combinações de feature, agregando pela qualidade. Em seguida, foi feita uma análise dos vinhos ruins com os vinhos bons, e algumas carascterísticas puderam ser notadas.
sns.pairplot(df,hue = 'quality_label',x_vars = elements_columns,y_vars = acid_columns)
sns.pairplot(df,hue = 'quality_label',x_vars = elements_columns,y_vars = elements_columns)
sns.pairplot(df,hue = 'quality_label',x_vars = elements_columns,y_vars = other_columns)
sns.pairplot(df,hue = 'quality_label',x_vars = acid_columns,y_vars = other_columns)
sns.pairplot(df,hue = 'quality_label',x_vars = acid_columns,y_vars = acid_columns)
Análise dos vinhos ótimos com os vinhos ruins
É notório que em relação ao alcohol e sulphates, os vinhos ruins estão concentrados nas áreas inferiores à esquerda (menor valor de álcohol e concentração de sulphates), e os vinhos bons para maiores valores de alcohol e sulphate.
É notório que em relação a densidade e alcohol, os vinhos ruins estão concentrados na área de maior densidade e menor concetração alcólica.
sns.pairplot(df[(df["quality_category"] == 0) | (df["quality_category"] == 2)],hue = 'quality_label',x_vars = elements_columns,y_vars = elements_columns)
Podemos perceber melhor essa correlação, plotando em um gráfico maior a relação da feature alcohol com sulphates, em vinhos ruins e bons.
data = df[(df["quality_category"] == 0) | (df["quality_category"] == 2)]
sns.lmplot(x="alcohol", y="sulphates", hue='quality_label', data=data,fit_reg=False)
Podemos perceber uma divisão bem clara entre alcohol e density, para vinhos de qualidade ruim e ótima
sns.pairplot(df[(df["quality_category"] == 0) | (df["quality_category"] == 2)],hue = 'quality_label',x_vars = other_columns,y_vars = elements_columns)
Visualizando melhor o scatterplot:
data = df[(df["quality_category"] == 0) | (df["quality_category"] == 2)]
sns.lmplot(x="alcohol", y="density", hue='quality_label', data=data,fit_reg=False)
from sklearn import model_selection
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
from sklearn.metrics import accuracy_score
from sklearn.metrics import average_precision_score
from sklearn.metrics import f1_score
from sklearn.model_selection import GridSearchCV
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
import itertools
from sklearn.preprocessing import LabelBinarizer
from sklearn.metrics import precision_recall_fscore_support
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
import xgboost as xgb
from sklearn.decomposition import PCA
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import LinearSVC
from sklearn.naive_bayes import GaussianNB
def normalize(v):
norm=np.linalg.norm(v, ord=1)
if norm==0:
norm=np.finfo(v.dtype).eps
return v/norm
Vamos normalizar os valores pela média e desvio padrão
def prepare_data(df,drop_columns = ["quality_category","quality_label"]):
x = df.drop(drop_columns,axis=1)
x["type"] = x["type"].map(lambda x: {"White":0,"Red":1}[x]).astype(int)
for column in x.columns:
if column!="quality" and column!="type" and column!="quality_label" and column!="quality_category":
x[column]=(x[column]-(x[column].mean()))/(x[column].std())
return x
Em todos os modelos, utilizaremos o GridSearch para achar os melhores parâmetros.
df2 = prepare_data(df)
x = df2.loc[:,list(set(df2.columns)-set(["quality"]))].values
y= df2.loc[:,"quality"].values
cv = model_selection.StratifiedKFold(n_splits=3)
X_traincv, X_testcv, y_traincv, y_testcv = model_selection.train_test_split(x,
y,
test_size=0.33,
random_state=4,
stratify=y)
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print(cm)
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, cm[i, j],
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
def class_report(y_true, y_pred, y_score=None, average='micro'):
if y_true.shape != y_pred.shape:
print("Error! y_true %s is not the same shape as y_pred %s" % (
y_true.shape,
y_pred.shape)
)
return
lb = LabelBinarizer()
if len(y_true.shape) == 1:
lb.fit(y_true)
#Value counts of predictions
labels, cnt = np.unique(
y_true,
return_counts=True)
n_classes = len(labels)
pred_cnt = pd.Series(cnt, index=labels)
metrics_summary = precision_recall_fscore_support(
y_true=y_true,
y_pred=y_pred,
labels=labels)
avg = list(precision_recall_fscore_support(
y_true=y_true,
y_pred=y_pred,
average='weighted'))
metrics_sum_index = ['precision', 'recall', 'f1-score', 'support']
class_report_df = pd.DataFrame(
list(metrics_summary),
index=metrics_sum_index,
columns=labels)
support = class_report_df.loc['support']
total = support.sum()
class_report_df['avg / total'] = avg[:-1] + [total]
class_report_df = class_report_df.T
class_report_df['pred'] = pred_cnt
class_report_df['pred'].iloc[-1] = total
if not (y_score is None):
fpr = dict()
tpr = dict()
roc_auc = dict()
for label_it, label in enumerate(labels):
fpr[label], tpr[label], _ = roc_curve(
(y_true == label).astype(int),
y_score[:, label_it])
roc_auc[label] = auc(fpr[label], tpr[label])
if average == 'micro':
if n_classes <= 2:
fpr["avg / total"], tpr["avg / total"], _ = roc_curve(
lb.transform(y_true).ravel(),
y_score[:, 1].ravel())
else:
fpr["avg / total"], tpr["avg / total"], _ = roc_curve(
lb.transform(y_true).ravel(),
y_score.ravel())
roc_auc["avg / total"] = auc(
fpr["avg / total"],
tpr["avg / total"])
elif average == 'macro':
# First aggregate all false positive rates
all_fpr = np.unique(np.concatenate([
fpr[i] for i in labels]
))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in labels:
mean_tpr += interp(all_fpr, fpr[i], tpr[i])
# Finally average it and compute AUC
mean_tpr /= n_classes
fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["avg / total"] = auc(fpr["macro"], tpr["macro"])
class_report_df['AUC'] = pd.Series(roc_auc)
return class_report_df
def plot_learning_curve(estimator,
title,
X,
y,
ylim=None,
cv=None,
n_jobs=-1,
train_sizes=np.linspace(.1, 1.0, 5)):
plt.figure(figsize=(16,8))
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes, train_scores, test_scores = model_selection.learning_curve(estimator,
X, y, cv=cv,
n_jobs=n_jobs,
train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1, color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Cross-validation score")
plt.legend(loc="best")
return plt
def model_fit_transform_and_eval(model,params,cv, x_train, y_train, x_test, y_test):
grid = GridSearchCV(model,params, scoring = 'accuracy', cv=cv,n_jobs=-1).fit(x_train,y_train)
best_model = grid.best_estimator_
y_pred = best_model.predict(x_test)
best_model_confuncion_matrix = confusion_matrix(y_test, y_pred)
best_model_report = class_report(y_test, y_pred)
return {"best_model":best_model,"confusion_matrix":best_model_confuncion_matrix,"model_report":best_model_report, "best_params":grid.best_params_}
Utilizaremos o GridSearch para selecionar:
Cs = np.linspace(0.1,100,40)
param_grid=dict(estimator__C=Cs, estimator__penalty=["l1","l2"],estimator__class_weight=["balanced",None])
model = OneVsRestClassifier(LogisticRegression())
clf_logistic_regression = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
Os melhores parâmetros para o melhor estimador
clf_logistic_regression["best_params"]
Plotando a curva de aprendizado para o melhor estimador
plot_learning_curve(clf_logistic_regression["best_model"],
"One Vs Rest with Logistic Regression",
X_traincv,
y_traincv,
cv=cv)
A tabela abaixo indica os valores das métricas utilizadas para avaliar os estimadores.
O modelo teve uma precisão geral de 53%
O modelo acerta 58% dos vinhos de qualidade 5, 51% dos vinhos de qualidade 6, 49% dos vinhos de qualidade 7 e 100% ds vinhos de qualidade 4
O modelo falha completamente em relação aos vinhos de qualidade 3,8 e 9
clf_logistic_regression["model_report"]
plot_confusion_matrix(clf_logistic_regression["confusion_matrix"], ["3","4","5","6","7","8","9"])
O algoritmo one vs the rest, junto com regressão logística, produz n_classes algoritmos de regressão logística. Um algoritmo para cada classe. Sendo assim, podemos plotar a importância das features de cada algoritmo de cada classe. O que significa que saberemos feature foi mais importante para o algoritmo prever aquela classe.
O tipo de vinho foi a feature mais importante para a predição do vinho de Qualidade 3 e 4
Density tem efeitos completamentes diferentes para os vinhos de categoria 6,7 , e são as features mais importantes (em módulo)
Citric Acid foi uma das features que obteve menos importância em todos os 7 estimadores
columns_data = list(set(columns_data)-set(["quality"]))
lower,upper = -1,1
fig = plt.figure(figsize=(20,20))
for index in range(7):
logistic_regression_feature_importance = normalize(clf_logistic_regression["best_model"].estimators_[index].coef_[0])
ax = fig.add_subplot(4,2,index+1)
ax.barh(columns_data, logistic_regression_feature_importance , align='center')
ax.set_title("Vinho Categoria "+str(index+3))
Utilizaremos o GridSearch para selecionar:
model = RandomForestClassifier()
param_grid = {"class_weight":["balanced",None],'bootstrap': [True, False],
'max_depth': [10, 20, 30, None],
'max_features': ['auto', 'sqrt'],
'min_samples_leaf': [1, 2, 4],
'min_samples_split': [2, 5, 10],
'n_estimators': [400, 600, 800]}
clf_random_forest = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
clf_random_forest["best_params"]
Plotando a curva de aprendizado para o melhor estimador
plot_learning_curve(clf_random_forest["best_model"],
"Random Forest Classifier",
X_traincv,
y_traincv,
cv=cv)
A tabela abaixo indica os valores das métricas utilizadas para avaliar os estimadores.
clf_random_forest["model_report"]
plot_confusion_matrix(clf_random_forest["confusion_matrix"], ["3","4","5","6","7","8","9"])
random_forest_feature_importance = clf_random_forest["best_model"].feature_importances_
random_forest_feature_importance = normalize(random_forest_feature_importance)
O gráfico abaixo mostra a importância das features, n algoritmo de Random Forest. As três features mais importantes são:
1) Alcohol
2) Density
3) Volatile Acidity
fig = plt.figure(figsize=(12,8))
plt.barh(['citric acid', 'chlorides', 'alcohol', 'free sulfur dioxide', 'fixed acidity','type','pH','residual sugar','total sulfur dioxide','sulphates','density','volatile acidity'], random_forest_feature_importance , align='center')
plt.title('Random Forest - Feature Importance')
Utilizaremos o GridSearch para selecionar:
model = DecisionTreeClassifier()
param_grid = {"class_weight":["balanced",None],
'max_depth': range(1,40),
'max_features': ['auto', 'sqrt'],
'min_samples_leaf': [1,2,3,4],
'min_samples_split': [2, 5, 10]
}
clf_decision_tree = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
Plotando a curva de aprendizagem
plot_learning_curve(clf_decision_tree["best_model"],
"Decision Tree Classifier",
X_traincv,
y_traincv,
cv=cv)
A tabela abaixo indica os valores das métricas utilizadas para avaliar os estimadores.
O algoritmo de árvore de decisão obteve 58.2% de precisão;
O algoritmo não teve acertividade nos vinhos de qualidade 3 e 9;
O algoritmo teve uma precisão maior para os vinhos de qualidade 5 e 6.
clf_decision_tree["model_report"]
clf_decision_tree["model_report"]["precision"].loc["avg / total"]
plot_confusion_matrix(clf_decision_tree["confusion_matrix"], ["3","4","5","6","7","8","9"])
Utilizamos o algoritmo K - Nearest Neighbor. Por meio do GridSearch, selecionamos os pelos parâmetros:
metrics = ['minkowski','euclidean','manhattan']
weights = ['uniform','distance']
numNeighbors = np.arange(5,12)
model = KNeighborsClassifier()
param_grid = dict(metric=metrics,weights=weights,n_neighbors=numNeighbors)
clf_knn = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
clf_knn["best_params"]
Plotando a melhor curva
plot_learning_curve(clf_knn["best_model"],
"kNN Classifier",
X_traincv,
y_traincv,
cv=cv)
O algoritmo obteve 64.8% de precisão.
clf_knn["model_report"]
plot_confusion_matrix(clf_knn["confusion_matrix"], ["3","4","5","6","7","8","9"])
model = LinearSVC(multi_class='ovr')
Cs = np.linspace(0.1,100,200)
gammas = np.logspace(-5, 0, 10)
param_grid=dict(C=Cs, class_weight=["balanced",None])
clf_svm = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
clf_svm["best_params"]
Plotando a curva de aprendizagem:
plot_learning_curve(clf_svm["best_model"],
"SVM Classifier",
X_traincv,
y_traincv,
cv=cv)
A tabela abaixo indica os valores das métricas utilizadas para avaliar os estimadores. SVM deu um resultado ruim em todas as classes, errando 100% dos vinhos de qualidade, 3, 4, 8 e 9 A precisão do modelo foi de 44%
clf_svm["model_report"]
plot_confusion_matrix(clf_svm["confusion_matrix"], ["3","4","5","6","7","8","9"])
param_grid= {
'min_child_weight': [1, 5, 10],
'gamma': [0.5, 1, 1.5, 2, 5],
'subsample': [0.6, 0.8, 1.0],
'colsample_bytree': [0.6, 0.8, 1.0],
'max_depth': [3, 4, 5],
}
model = xgb.XGBClassifier()
clf_xgboost = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
clf_xgboost["best_params"]
plot_learning_curve(clf_xgboost["best_model"],
"XgBoost Classifier",
X_traincv,
y_traincv,
cv=cv)
O modelo obteve 62.6% de precisão , porém prevendo erroneamente todos os casos dos vinhos de qualidade 3 e 9;
clf_xgboost["model_report"]
plot_confusion_matrix(clf_xgboost["confusion_matrix"], ["3","4","5","6","7","8","9"])
clf_xgboost["best_model"].feature_importances_
fig = plt.figure(figsize=(12,8))
plt.barh(['citric acid', 'chlorides', 'alcohol', 'free sulfur dioxide', 'fixed acidity','type','pH','residual sugar','total sulfur dioxide','sulphates','density','volatile acidity'], clf_xgboost["best_model"].feature_importances_ , align='center')
plt.title('xGBoost - Feature Importance')
model = GaussianNB()
param_grid = {}
clf_mnb = model_fit_transform_and_eval(model,param_grid,cv, X_traincv, y_traincv, X_testcv, y_testcv)
plot_learning_curve(clf_mnb["best_model"],
"Gaussian Naive Classifier",
X_traincv,
y_traincv,
cv=cv)
clf_mnb["model_report"]
plot_confusion_matrix(clf_mnb["confusion_matrix"], ["3","4","5","6","7","8","9"])
fig = plt.figure(figsize=(12,8))
plt.barh(['Gaussian Naive Bayes', 'Logistic Regression', 'SVM', 'Random Forest', 'KNN','Decision Tree','xGBoost'], [clf_mnb["model_report"]["precision"].loc["avg / total"],clf_logistic_regression["model_report"]["precision"].loc["avg / total"],clf_svm["model_report"]["precision"].loc["avg / total"],clf_random_forest["model_report"]["precision"].loc["avg / total"],clf_knn["model_report"]["precision"].loc["avg / total"],clf_decision_tree["model_report"]["precision"].loc["avg / total"],clf_xgboost["model_report"]["precision"].loc["avg / total"]], align='center')
plt.title('Comparação dos Algoritmos - Precisão')
Podemos reduzir o número de features, perdendo um pouco da qualidade dos dados, com objetivo de tornar o modelo não somente mais fácil mas também com menos features, o que pode tornar os dados mais claros para serem analizados e otimizados pelos algoritmos. Basicamente iremos representar nossos dados no espaço dos autovetores da matrix X das features.
Iremos tentar manter 95% da variância e obter o número de componentes necessárias para isso.
pca = PCA(.95)
pca.fit(X_traincv)
X_traincv_pca = pca.transform(X_traincv)
X_testcv_pca = pca.transform(X_testcv)
Para manter 95% da variância, precisamos de 9 componentes (antes eram 12):
pca.n_components_
Vamos escolher os melhores parâmetros utilizando GridSearch, no primeiro modelo que testamos (One Vs The Rest com Regressão Logística)
Cs = np.linspace(0.1,100,40)
param_grid=dict(estimator__C=Cs, estimator__penalty=["l1","l2"],estimator__class_weight=["balanced",None])
model = OneVsRestClassifier(LogisticRegression())
clf_logistic_regression_pca = model_fit_transform_and_eval(model,param_grid,cv, X_traincv_pca, y_traincv, X_testcv_pca, y_testcv)
clf_logistic_regression_pca["best_params"]
plot_learning_curve(clf_logistic_regression_pca["best_model"],
"One vs Rest Classifier / Logistic Regression / PCA",
X_traincv,
y_traincv,
cv=cv)
O algoritmo obteve 51% de precisão geral, obtendo um resultado inferior ao primeiro algoritmo utilizado
clf_logistic_regression_pca["model_report"]
clf_logistic_regression_pca["best_params"]
plot_confusion_matrix(clf_logistic_regression_pca["confusion_matrix"], ["3","4","5","6","7","8","9"])
Nesse caso, iremos classificar somente os vinhos em Ruins, Médios ou Ótimos
df2 = prepare_data(df,["quality_label","quality"])
x = df2.loc[:,list(set(df2.columns)-set(["quality_category"]))].values
y = df2.loc[:,"quality_category"].values
cv = model_selection.StratifiedKFold(n_splits=3)
X_traincv2, X_testcv2, y_traincv2, y_testcv2 = model_selection.train_test_split(x,
y,
test_size=0.33,
random_state=4,
stratify=y)
Cs = np.linspace(0.1,100,40)
param_grid=dict(estimator__C=Cs, estimator__penalty=["l1","l2"],estimator__class_weight=["balanced",None])
model = OneVsRestClassifier(LogisticRegression())
clf_logistic_regression2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_logistic_regression2["best_params"]
plot_learning_curve(clf_logistic_regression2["best_model"],
"One vs Rest Classifier / Logistic Regression",
X_traincv2,
y_traincv2,
cv=cv)
O algoritmo obteve 76.1% de precisão, acertando todos os vinhos de qualidade ruim.
clf_logistic_regression2["model_report"]
plot_confusion_matrix(clf_logistic_regression2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
model = RandomForestClassifier()
param_grid = {"class_weight":["balanced",None],'bootstrap': [True, False],
'max_depth': [10, 20, 30, None],
'max_features': ['auto', 'sqrt'],
'min_samples_leaf': [1, 2, 4],
'min_samples_split': [2, 5, 10],
'n_estimators': [400, 600, 800]}
clf_random_forest2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_random_forest2["best_params"]
plot_learning_curve(clf_random_forest2["best_model"],
"Random Forest",
X_traincv2,
y_traincv2,
cv=cv)
O algoritmo obteve 83.9% de precisão, obtendo melhor resultado prevendo os vinhos de qualidade média.
clf_random_forest2["model_report"]
plot_confusion_matrix(clf_random_forest2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
param_grid= {
'min_child_weight': [1, 5, 10],
'gamma': [0.5, 1, 1.5, 2, 5],
'subsample': [0.6, 0.8, 1.0],
'colsample_bytree': [0.6, 0.8, 1.0],
'max_depth': [3, 4, 5],
}
model = xgb.XGBClassifier()
clf_xgboost2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_xgboost2["best_params"]
plot_learning_curve(clf_xgboost2["best_model"],
"XgBoost",
X_traincv2,
y_traincv2,
cv=cv)
O algoritmo obteve 80.1% de precisão, obtendo um resultado ruim nos vinhos de qualidade ruim.
clf_xgboost2["model_report"]
plot_confusion_matrix(clf_xgboost2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
model = DecisionTreeClassifier()
param_grid = {"class_weight":["balanced",None],
'max_depth': range(1,40),
'max_features': ['auto', 'sqrt'],
'min_samples_leaf': [1,2,3,4],
'min_samples_split': [2, 5, 10]
}
clf_decision_tree2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_decision_tree2["best_params"]
plot_learning_curve(clf_decision_tree2["best_model"],
"Árvore de Decisão",
X_traincv2,
y_traincv2,
cv=cv)
O algoritmo obteve uma precisão de 78.0%, com resultado ruim nos vinhos de qualidade baixa (25.8%)
clf_decision_tree2["model_report"]
plot_confusion_matrix(clf_decision_tree2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
metrics = ['minkowski','euclidean','manhattan']
weights = ['uniform','distance'] #10.0**np.arange(-5,4)
numNeighbors = np.arange(5,12)
model = KNeighborsClassifier()
param_grid = dict(metric=metrics,weights=weights,n_neighbors=numNeighbors)
clf_knn2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_knn2["best_params"]
plot_learning_curve(clf_knn2["best_model"],
"KNN",
X_traincv2,
y_traincv2,
cv=cv)
O algoritmo obteve precisão de 82.3% prevendo melhor os vinhos de qualidade média
clf_knn2["model_report"]
plot_confusion_matrix(clf_knn2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
model = LinearSVC(multi_class='ovr')
Cs = np.linspace(0.1,100,200)
gammas = np.logspace(-5, 0, 10)
param_grid=dict(C=Cs, class_weight=["balanced",None])
clf_svm2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
clf_svm2["best_params"]
plot_learning_curve(clf_svm2["best_model"],
"SVM",
X_traincv2,
y_traincv2,
cv=cv)
O modelo obteve 72.1% de precisão, porem resultado ruim nos vinhos de qualidade baixa
clf_svm2["model_report"]
plot_confusion_matrix(clf_svm2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
model = GaussianNB()
param_grid = {}
clf_mnb2 = model_fit_transform_and_eval(model,param_grid,cv, X_traincv2, y_traincv2, X_testcv2, y_testcv2)
plot_learning_curve(clf_mnb2["best_model"],
"Gaussian Naive Classifier",
X_traincv2,
y_traincv2,
cv=cv)
clf_mnb2["model_report"]
plot_confusion_matrix(clf_mnb2["confusion_matrix"], ["Ruim","Médio","Ótimo"])
fig = plt.figure(figsize=(12,8))
plt.barh(['Gaussian Naive Bayes', 'Logistic Regression', 'SVM', 'Random Forest', 'KNN','Decision Tree','xGBoost'], [clf_mnb2["model_report"]["precision"].loc["avg / total"],clf_logistic_regression2["model_report"]["precision"].loc["avg / total"],clf_svm2["model_report"]["precision"].loc["avg / total"],clf_random_forest2["model_report"]["precision"].loc["avg / total"],clf_knn2["model_report"]["precision"].loc["avg / total"],clf_decision_tree2["model_report"]["precision"].loc["avg / total"],clf_xgboost2["model_report"]["precision"].loc["avg / total"]], align='center')
plt.title('Comparação dos Algoritmos - Precisão')